package us.mmapp.entities;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import us.mmapp.entities.FriendEntity.FriendState;
import us.mmapp.util.ApplicationData;
import us.mmapp.util.DBOpenHelper;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;

public class ObjectEntity {
	private String localId; // the localId the _ID from phone's database
	private long id; // id of the object (server side)
	private long uid; // uid
	private long date_created;
	private long date_modified;
	private int type;
	private String title;
	private String description;
	private String local_location;
	private String local_thumb;
	private String url;
	private String url_thumb;
	private int privacy;
	private double latitude;
	private double longitude;
	private boolean synced;
	private List<String> tags;
	private List<FieldEntity> extraFields;
	private List<CommentEntity> comments;
	
	private static final String NAME_LOCAL_ID="localId";
	private static final String NAME_ID = "id";
	private static final String NAME_UID = "uid";
	private static final String NAME_DATE_CREATED = "date_created";
	private static final String NAME_DATE_MODIFIED = "date_modified";
	private static final String NAME_TYPE = "type";
	private static final String NAME_TITLE = "title";
	private static final String NAME_DESCRIPTION = "description";
	private static final String NAME_LOCAL_LOCATION="local_location";
	private static final String NAME_LOCAL_THUMB = "local_thumb";
	private static final String NAME_URL = "url";
	private static final String NAME_URL_THUMB = "thumb_url";
	private static final String NAME_PRIVACY = "privacy";
	private static final String NAME_LATITUDE = "latitude";
	private static final String NAME_LONGITUDE = "longitude";
	private static final String NAME_TAGS = "tags";
	private static final String NAME_EXTRA = "extra";
	private static final String NAME_COMMENTS = "comments";
	private static final String NAME_SYNCED = "synced";
	
	public static ArrayList<ObjectEntity> getAllObjects(Context c)
	{
		ArrayList<ObjectEntity> allObjects=new ArrayList<ObjectEntity>();
		DBOpenHelper data=new DBOpenHelper(c, "mmAppDB", DBOpenHelper.VERSION);
		SQLiteDatabase db=data.getReadableDatabase();
        Cursor dbObjects=db.rawQuery("SELECT * FROM OBJECTS", null);
        HashMap<Long, FriendEntity> friends = ApplicationData.getFriends();
        while(dbObjects.moveToNext())
        {
        	// of the user
        	long uid = dbObjects.getInt(DBOpenHelper.uid);
        	if(uid == ApplicationData.getUserId())
        		allObjects.add(new ObjectEntity(c, dbObjects.getLong(dbObjects.getColumnIndex(DBOpenHelper.ID))));
        	else if (friends != null && friends.containsKey(uid) && friends.get(uid).getState() == FriendState.ACCEPTED
        			&& 0 != dbObjects.getInt(dbObjects.getColumnIndex(DBOpenHelper.PRIVACY)))
        	{
        		// from a friend 
        		allObjects.add(new ObjectEntity(c, dbObjects.getLong(dbObjects.getColumnIndex(DBOpenHelper.ID))));
        	}
        }
        dbObjects.close();
        db.close();
        data.close();
        return allObjects;
	}
	public ObjectEntity(JSONObject obj)
	{
		// construct an ObjectEntity from the JSONObject
		// get local id
		try {
			setLocalId(obj.getString(NAME_LOCAL_ID));
		} catch (JSONException e) {
			//Log.e("OBJECT ENTITY: ", e.getMessage());
		}
		// get id
		try {
			setId(obj.getLong(NAME_ID));
			setLocalId(obj.getLong(NAME_ID) + "");
		} catch (JSONException e) {
			Log.e("OBJECT ENTITY: ", e.getMessage());
		}
		//get date created
		try{
			setDateCreated(obj.getLong(NAME_DATE_CREATED));
		} catch (JSONException e) {
			Log.e("OBJECT ENTITY: ", e.getMessage());
		}
		//get date modified
		try{
			setDateCreated(obj.getLong(NAME_DATE_MODIFIED));
		} catch (JSONException e) {
			Log.e("OBJECT ENTITY: ", e.getMessage());
		}
		// get uid
		try {
			setUid(obj.getLong(NAME_UID));
		} catch (JSONException e) {
			Log.e("OBJECT ENTITY: ", e.getMessage());
		}
		
		//get type
		try {
			setType(obj.getInt(NAME_TYPE));
		} catch (JSONException e) {
			Log.e("OBJECT ENTITY: ", e.getMessage());
		}
		
		// get title
		try {
			setTitle(obj.getString(NAME_TITLE));
		} catch (JSONException e) {
			Log.e("OBJECT ENTITY: ", e.getMessage());
		}
		
		// get description
		try {
			setDescription(obj.getString(NAME_DESCRIPTION));
		} catch (JSONException e) {
			Log.e("OBJECT ENTITY: ", e.getMessage());
		}
		
		// get url
		try {
			setUrl(obj.getString(NAME_URL));
		} catch (JSONException e) {
			Log.e("OBJECT ENTITY: ", e.getMessage());
		}
		
		// get url_thumb
		try {
			setUrl_thumb(obj.getString(NAME_URL_THUMB));
		} catch (JSONException e) {
			Log.e("OBJECT ENTITY: ", e.getMessage());
		}
		
		// get privacy
		try {
			setPrivacy(obj.getInt(NAME_PRIVACY));
		} catch (JSONException e) {
			Log.e("OBJECT ENTITY: ", e.getMessage());
		}
		
		// get latitude
		try {
			setLatitude(obj.getDouble(NAME_LATITUDE));
		} catch (JSONException e) {
			Log.e("OBJECT ENTITY: ", e.getMessage());
		}
		
		// get longitude
		try {
			setLongitude(obj.getDouble(NAME_LONGITUDE));
		} catch (JSONException e) {
			Log.e("OBJECT ENTITY: ", e.getMessage());
		}
		try {
			setSynced(obj.getBoolean(NAME_SYNCED));
		} catch (JSONException e) {
			//Log.e("OBJECT ENTITY: ", e.getMessage());
		}
		// get tags
		tags = new ArrayList<String>();	
		try {
			JSONArray tagsArray = obj.getJSONArray(NAME_TAGS);
			for (int i = 0; i < tagsArray.length(); ++i)
			{
				tags.add(tagsArray.getString(i));
			}
		} catch (JSONException e) {
			Log.e("OBJECT ENTITY: ", e.getMessage());
		}
		
		// get extra
		extraFields = new ArrayList<FieldEntity>();
		try {
			JSONArray fields = obj.getJSONArray(NAME_EXTRA);
			for (int i = 0; i < fields.length(); ++i)
				extraFields.add(new FieldEntity(fields.getJSONObject(i)));
		} catch (JSONException e) {
			//Log.e("OBJECT ENTITY: ", e.getMessage());
		}
		
		// get comments
		comments = new ArrayList<CommentEntity>();
		try
		{
			JSONArray c = obj.getJSONArray(NAME_COMMENTS);
			for (int i = 0; i < c.length(); ++i)
				comments.add(new CommentEntity(c.getJSONObject(i)));
		}
		catch (JSONException e)
		{
			Log.e("OBJECT ENTITY: ", e.getMessage());
		}
	}
	public ObjectEntity(Context context, Long databaseID)
	{
		DBOpenHelper data = new DBOpenHelper(context, "mmAppDB", DBOpenHelper.VERSION);
		SQLiteDatabase db=data.getReadableDatabase();
		Cursor dbObjects=db.rawQuery("Select * from OBJECTS where id='"+databaseID+"'", null);
		if(dbObjects.moveToNext())
		{
			setLocalId(dbObjects.getString(0));
			setId(dbObjects.getLong(1));
			setUid(dbObjects.getLong(2));
			setType(dbObjects.getInt(4));
			setTitle(dbObjects.getString(5));
			setDescription(dbObjects.getString(6));
			setPrivacy(dbObjects.getInt(7));
			setDateCreated(dbObjects.getLong(8));
			setDateModified(dbObjects.getLong(9));
			setLatitude(dbObjects.getDouble(10));
			setLongitude(dbObjects.getDouble(11));
			setUrl(dbObjects.getString(12));
			setUrl_thumb(dbObjects.getString(13));
			
			setSynced(false);
			if(dbObjects.getInt(14)==1)
				setSynced(true);
			setLocalLocation(dbObjects.getString(dbObjects.getColumnIndex(DBOpenHelper.STOREAGE_LOCATION)));
			setLocalThumb(dbObjects.getString(dbObjects.getColumnIndex(DBOpenHelper.LOCAL_THUMB)));
			
		}
		dbObjects.close();
		// Log.i(""+id, ""+id);
		dbObjects=db.rawQuery("Select * from TAGS where id='"+databaseID+"'", null);
		if(dbObjects.moveToNext())
		{
			String tagString=dbObjects.getString(1);
			if (tagString == null)
				tagString = "";
			tags=Arrays.asList(tagString.split(" "));
		}
		dbObjects.close();
		
		Cursor dbObjects1=db.rawQuery("Select * from COMMENTS where OID="+id, null);
		dbObjects=db.rawQuery("Select rowid from comments where oid="+id, null);
		comments=new ArrayList<CommentEntity>();
		while(dbObjects1.moveToNext() && dbObjects.moveToNext())
		{
			
			comments.add(new CommentEntity(dbObjects.getInt(0), dbObjects1.getLong(0), dbObjects1.getLong(1), dbObjects1.getLong(2), dbObjects1.getString(3)));
			//comments.add(new CommentEntity(dbObjects1));
		}
		dbObjects1.close();
		dbObjects.close();
		
		extraFields=new ArrayList<FieldEntity>();
		Cursor dbObjects2=db.rawQuery("Select * from EXTRA_FIELDS where OID="+id, null);
		dbObjects=db.rawQuery("Select rowid from extra_fields where oid="+id, null);
		while(dbObjects2.moveToNext() && dbObjects.moveToNext())
		{			
			extraFields.add(new FieldEntity(dbObjects.getInt(0), dbObjects2.getString(0), dbObjects2.getString(1), dbObjects2.getInt(2), dbObjects2.getInt(3)));
			//extraFields.add(new FieldEntity(dbObjects2));
		}
		dbObjects.close();
		dbObjects2.close();
		data.close();
	}
	public JSONObject toJSON()
	{
		JSONObject j=new JSONObject();
		try
		{
			j.put(NAME_LOCAL_ID, localId);
			j.put(NAME_ID, id);
			j.put(NAME_UID, uid);
			j.put(NAME_DATE_CREATED, date_created);
			j.put(NAME_DATE_MODIFIED, date_modified);
			j.put(NAME_TYPE, type);
			j.put(NAME_TITLE, title);
			j.put(NAME_DESCRIPTION, description);
			j.put(NAME_LOCAL_LOCATION, local_location);
			j.put(NAME_URL, url);
			j.put(NAME_URL_THUMB, url_thumb);
			j.put(NAME_PRIVACY, privacy);
			j.put(NAME_LATITUDE, latitude);
			j.put(NAME_LONGITUDE, longitude);
			j.put(NAME_SYNCED, synced);
			j.put(NAME_LOCAL_THUMB, local_thumb);
			try{
				Iterator<String> i=tags.iterator();
				while(i.hasNext())
				{
					j.accumulate(NAME_TAGS, i.next());
				}
			}
			catch(NullPointerException e)
			{
				Log.i("No Tags", e.getMessage());
			}
			try{
				Iterator<FieldEntity> iter=extraFields.iterator();
				while(iter.hasNext())
				{
					j.accumulate(NAME_EXTRA, iter.next().toJson());
				}
			}
			catch(NullPointerException e)
			{
				Log.i("No Field Entities", e.getMessage());
			}
			try{
				Iterator<CommentEntity> cIter=comments.iterator();
				while(cIter.hasNext())
				{
					j.accumulate(NAME_COMMENTS, cIter.next().toJson());
				}	
			}
			catch(NullPointerException e)
			{
				Log.i("No Comment Entities", e.getMessage());
			}
		}
		catch (JSONException e)
		{
			e.printStackTrace();
		}
		return j;
	}
	public void insertDB(Context context)
	{
		DBOpenHelper data=new DBOpenHelper(context, "mmAppDB", DBOpenHelper.VERSION);
		SQLiteDatabase db=data.getReadableDatabase();
		Cursor c=db.rawQuery("Select * from objects where ID='"+localId+"'", null);
		
		if(c.moveToNext())
		{
			local_location=c.getString(3);
			local_thumb=c.getString(15);
		}
		if (c != null)
			c.close();
		
		db.close();
		db=data.getWritableDatabase();
		
		ContentValues cv=new ContentValues();
		
		cv.put(DBOpenHelper.ID, localId);
		cv.put(DBOpenHelper.STOREAGE_LOCATION, local_location);
		cv.put(DBOpenHelper.UID, uid);
		cv.put(DBOpenHelper.TYPE, type);
		cv.put(DBOpenHelper.DATE_CREATED, date_created);
		cv.put(DBOpenHelper.LATITUDE, latitude);
		cv.put(DBOpenHelper.LONGITUDE, longitude);
		cv.put(DBOpenHelper.TITLE, title);
		cv.put(DBOpenHelper.DESCRIPTION, description);
		cv.put(DBOpenHelper.PRIVACY, privacy);
		cv.put(DBOpenHelper.DATE_MODIFIED, date_modified);
		cv.put(DBOpenHelper.SID, id);
		cv.put(DBOpenHelper.SYNCED, synced);
		cv.put(DBOpenHelper.URL, url);
		cv.put(DBOpenHelper.URL_THUMB, url_thumb);
		cv.put(DBOpenHelper.LOCAL_THUMB, local_thumb);
		db.insertWithOnConflict("OBJECTS", null, cv, SQLiteDatabase.CONFLICT_REPLACE);
		cv.clear();
		cv.put("ID", localId);
		String tagsText = null;
		for(int i=0; i<tags.size(); i++)
		{
			tagsText=tags.get(i)+" "+tagsText;
		}
		cv.put("TAG", tagsText);
		db.insertWithOnConflict("TAGS", null, cv, SQLiteDatabase.CONFLICT_REPLACE);
		cv.clear();
		
		for(int i=0; i<extraFields.size(); i++)
		{
			extraFields.get(i).insertDB(db);
		}
		
		for(int i=0; i<comments.size(); i++)
		{
			comments.get(i).insertDB(db);
		}
		db.close();
	}
	public void setLocalThumb(String locThumb)
	{
		local_thumb=locThumb;
	}
	public String getLocalThumb()
	{
		return local_thumb;
	}
	public void setSynced(boolean sync)
	{
		synced=sync;
	}
	public boolean getSynced()
	{
		return synced;
	}
	public void setLocalLocation(String loc)
	{
		local_location=loc;
	}
	public String getLocalLocation()
	{
		return local_location;
	}
	public void setDateCreated(long date)
	{
		date_created=date;
	}
	public void setDateModified(long date)
	{
		date_modified=date;
	}
	public long getDateCreated()
	{
		return date_created;
	}
	public long getDateModified()
	{
		return date_modified;
	}
	public void setId(long id)
	{
		this.id = id;
	}

	public long getId()
	{
		return id;
	}

	public void setUid(long uid)
	{
		this.uid = uid;
	}

	public long getUid()
	{
		return uid;
	}

	public void setType(int type)
	{
		this.type = type;
	}

	public int getType()
	{
		return type;
	}

	public void setTitle(String title)
	{
		this.title = title;
	}

	public String getTitle()
	{
		return title;
	}

	public void setDescription(String description)
	{
		this.description = description;
	}

	public String getDescription()
	{
		return description;
	}

	public void setUrl(String url)
	{
		this.url = url;
	}

	public String getUrl()
	{
		return url;
	}

	public void setUrl_thumb(String url_thumb)
	{
		this.url_thumb = url_thumb;
	}

	public String getUrl_thumb()
	{
		return url_thumb;
	}

	public void setPrivacy(int privacy)
	{
		this.privacy = privacy;
	}

	public int getPrivacy()
	{
		return privacy;
	}

	public void setLatitude(double latitude)
	{
		this.latitude = latitude;
	}

	public double getLatitude()
	{
		return latitude;
	}

	public void setLongitude(double longitude)
	{
		this.longitude = longitude;
	}

	public double getLongitude()
	{
		return longitude;
	}

	public List<String> getTags()
	{
		return tags;
	}

	public void setTags(List<String> tags)
	{ 
		this.tags = tags;
	}

	public List<FieldEntity> getExtraFields()
	{
		return extraFields;
	}

	public void setExtraFields(List<FieldEntity> extraFields)
	{
		this.extraFields = extraFields;
	}

	public List<CommentEntity> getComments()
	{
		return comments;
	}

	public void setComments(List<CommentEntity> comments)
	{
		this.comments = comments;
	}

	public void setLocalId(String localId)
	{
		this.localId = localId;
	}

	public String getLocalId()
	{
		return localId;
	}

}
